Java Web Token 之 java 您所在的位置:网站首页 jwt java代码 Java Web Token 之 java

Java Web Token 之 java

2023-04-15 03:32| 来源: 网络整理| 查看: 265

文末附原文链接 -- 微信公众号首发Java JWT

java-jwt 是JSON Web Token(JWT) - RFC 7519 的实现。

Installation

Maven

com.auth0 java-jwt 3.4.0

Gradle

compile 'com.auth0:java-jwt:3.4.0'

Available Algorithms

这个库通过下面罗列的算法实现了JWT校验和签名:

Usage

Pick the Algorithm

算法定义了如何验证和签名一个token(令牌)。在使用HMAC算法的情况下可以使用秘密(secret)进行实例化;在使用RSA和ECDSA算法的情况下可以使用密钥对或KeyProvider进行实例化。

当使用RSA和ECDSA算法时,只需要对JWT进行签名即可避免通过传递null值来指定公钥。当你只需要验证JWT时,可以使用私钥完成相同的操作。

Using static secrets or keys

//HMAC Algorithm algorithmHS = Algorithm.HMAC256("secret"); //RSA RSAPublicKey publicKey = //Get the key instance RSAPrivateKey privateKey = //Get the key instance Algorithm algorithmRS = Algorithm.RSA256(publicKey, privateKey);

Using a KeyProvider

通过使用KeyProvider,你可以在运行时更改用于验证令牌(token)的签名或为RSA或ECDSA算法签署新令牌的密钥。这可以通过实现 RSAKeyProvider 或 ESDSAKeyProvider 这一方式来实现:

getPublicKeyById(String kid) :该方法在token签名验证期间被调用,它会返回用来验证token的key。如果正在使用转置密钥,例如 JWK,它可以使用id获取正确的转置密钥。 getPrivateKey( ) ;它在令牌签名期间调用,它返回将用于签署JWT的密钥。 getPrivateKeyId( ) :它在令牌签名期间调用,它返回 getPrivateKey( ) 返回的key的id。此值优于 JWTCreator.Builder #withKeyId(String) 方法中设置的值。 如果你不需要设置kid值,请避免使用KeyProvider实例化算法。

下面的代码展示了 RSAKeyProvider是如何工作的:

final JwkStore jwkStore = new JwkStore("{JWKS_FILE_HOST}"); final RSAPrivateKey privateKey = //Get the key instance final String privateKeyId = //Create an Id for the above key RSAKeyProvider keyProvider = new RSAKeyProvider() { @Override public RSAPublicKey getPublicKeyById(String kid) { //Received 'kid' value might be null if it wasn't defined in the Token's header RSAPublicKey publicKey = jwkStore.get(kid); return (RSAPublicKey) publicKey; } @Override public RSAPrivateKey getPrivateKey() { return privateKey; } @Override public String getPrivateKeyId() { return privateKeyId; } }; Algorithm algorithm = Algorithm.RSA256(keyProvider); //Use the Algorithm to create and verify JWTs.

Create and Sign a Token

首先通过调用 JWT.create( ) 来创建 JWTCreator 的实例。在使用builder定义token需要有的自定义Claims。最终通过调用传入 算法(Algorithm)实例的 sign( ) 方法获取token字符串:

HS256 demo

try { Algorithm algorithm = Algorithm.HMAC256("secret"); String token = JWT.create() .withIssuer("auth0") .sign(algorithm); } catch (JWTCreationException exception){ //Invalid Signing }

RS256 demo

RSAPublicKey publicKey = //Get the key instance RSAPrivateKey privateKey = //Get the key instance try { Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey); String token = JWT.create() .withIssuer("auth0") .sign(algorithm); } catch (JWTCreationException exception){ //Invalid Signing configuration / Couldn't convert Claims. }

如果Claim不能被转换为JSON或者使用的Key在签名时不可用,那么就会抛出 JWTCreationException 异常。

Verify a Token

首先要通过调用传入了 Algorithm 实例的 JWT.require( ) 方法来获得 JWTVerifier 实例。如果你需要token带有指定的Claim值,可以通过builder来定义。并且 build( ) 方法会返回 JWTVerifier 的实例,同时该方法只需要定义一次就可以用来验证不同的token。最后,调用 verifier.verify( ) 同时传入token:

HS256 demo

String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE"; try { Algorithm algorithm = Algorithm.HMAC256("secret"); JWTVerifier verifier = JWT.require(algorithm) .withIssuer("auth0") .build(); //Reusable verifier instance DecodedJWT jwt = verifier.verify(token); } catch (JWTVerificationException exception){ //Invalid signature/claims }

RS256 demo

String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE"; RSAPublicKey publicKey = //Get the key instance RSAPrivateKey privateKey = //Get the key instance try { Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey); JWTVerifier verifier = JWT.require(algorithm) .withIssuer("auth0") .build(); //Reusable verifier instance DecodedJWT jwt = verifier.verify(token); } catch (JWTVerificationException exception){ //Invalid signature/claims }

如果token携带的签名无效或者 Claim不匹配,就会抛出 JWTVerificationException 异常。

Time Validation

JWT token可以包含一些用于验证它的日期相关信息:

该token是已发布的token: "iat" < TODAY该token还没有过期: "exp" > TODAY该token目前可用:"nbf" > TODAY

对日期的验证是在验证token时自动执行的,如果验证不通过则会抛出 JWTVerificationException 异常。

使用 acceptLeeway( ) 方法可以定义token的有效时间窗口:

JWTVerifier verifier = JWT.require(algorithm) .acceptLeeway(1) // 1 sec for nbf, iat and exp .build();

你还可以给特定的日期Claim设置自定义值:

JWTVerifier verifier = JWT.require(algorithm) .acceptLeeway(1) //1 sec for nbf and iat .acceptExpiresAt(5) //5 secs for exp .build();

如果你要在自己的 app/lib 中测试这个行为,你需要把 Verification 实例强制转换成 BaseVerification 类型,然后该实例的 build( ) 方法才能接收一个自定义的 Clock:

BaseVerification verification = (BaseVerification) JWT.require(algorithm) .acceptLeeway(1) .acceptExpiresAt(5); Clock clock = new CustomClock(); //Must implement Clock interface JWTVerifier verifier = verification.build(clock);

Decode a Token

String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE"; try { DecodedJWT jwt = JWT.decode(token); } catch (JWTDecodeException exception){ //Invalid token }

如果token的格式不对,又或者 header 或 payload 的不是JSON,那么就会抛出 JWTDecodeException 异常。

Header Claims

Algorithm ("alg")

返回值:当前算法名称 || null (没有在header中定义)

String algorithm = jwt.getAlgorithm();

Type ("typ")

返回值:当前type名称 || null (没有在header中定义)

String type = jwt.getType();

Content Type ("cty")

返回值:当前content type值 || null (没有在header中定义)

String contentType = jwt.getContentType();

Key Id ("kid")

返回值:当前key id || null (没有在header中定义)

String keyId = jwt.getKeyId();

Private Claims

要获取在header里的额外定义的Claims,可以调用 getHeaderClaim( ) ,并且传入 Claim 名称。该方法总是会返回一个 Claim,无论该Claim有没有值。调用 claim.isNull( ) 可以判断该 Claim中是否有值:

Claim claim = jwt.getHeaderClaim("owner");

使用 JWT.create( ) 创建token时,你可以通过调用 withHeader( ) 并传递 Map 对象来指定 header Claims:

Map headerClaims = new HashMap(); headerClaims.put("owner", "auth0");String token = JWT.create() .withHeader(headerClaims) .sign(algorithm);

The alg and typ values will always be included in the Header after the signing process.

Payload Claims

Issure ("iss")

返回值:当前Issuer value || null (没有在payload中定义)

String issuer = jwt.getIssuer();

Subject ("sub")

返回值:当前Subject value || null (没有在payload中定义)

String subject = jwt.getSubject();

Audience ("aud")

返回值:当前Audience value || null (没有在payload中定义)

List audience = jwt.getAudience();

Expiration Time ("exp")

返回值:当前Exporation time value || null (没有在payload中定义)

Date expiresAt = jwt.getExpiresAt();

Not Before ("nbf")

返回值:当前Not Before value || null (没有在payload中定义)

Date notBefore = jwt.getNotBefore();

Issued At ("iat")

返回值:当前Issued At value || null (没有在payload中定义)

Date issuedAt = jwt.getIssuedAt();

JWT ID ("jti")

返回值:当前JWT ID value || null (没有在payload中定义)

String id = jwt.getId();

Private Claims

要获取在token payload里的额外定义的Claims,可以调用 getClaim( ) ,并且传入 Claim 名称。该方法总是会返回一个 Claim,无论该Claim有没有值。调用 claim.isNull( ) 可以判断该 Claim中是否有值:

Map claims = jwt.getClaims(); //Key is the Claim name Claim claim = claims.get("isAdmin"); 或 Claim claim = jwt.getClaim("isAdmin");

当使用 JWT.create( ) 创建token的时候你可以通过 withClaim( ) 来创建自定义的Claim:

String token = JWT.create() .withClaim("name", 123) .withArrayClaim("array", new Integer[]{1, 2, 3}) .sign(algorithm);

当要验证之前定义的自定义Claim时,你可以通过雷同的操作来实现:

JWTVerifier verifier = JWT.require(algorithm) .withClaim("name", 123) .withArrayClaim("array", 1, 2, 3) .build();DecodedJWT jwt = verifier.verify("my.jwt.token");

Currently supported classes for custom JWT Claim creation and verification are: Boolean, Integer, Double, String, Date and Arrays of type String and Integer.

Claim Class

Claim 类是对Claim值的封装。它允许你可以获取各种类型的Claim。可用的辅助方法有:

Primitives

asBoolean( ):返回Boolean值 || null (如果无法转换)asInt( ):返回Integer值 || null (如果无法转换)asDouble( ):返回Double值 || null (如果无法转换)asLong( ):返回Long值 || null (如果无法转换)asString( ):返回String值 || null (如果无法转换)asDate( ):返回Date值 || null (如果无法转换) 该函数的目标值必须是一个 NumericDate (Unix Epoch/Timestamp)

【注】JWT 标准中规定所有的NumericDate必须是秒数

Custom Classes and Collections

要以集合的形式获取Claim,你需要提供被转化的数据的类型:

as(class):返回该类型的值。对于集合,你应该使用 asArray 和 asList 方法。asMap( ):返回MapasArray(class):返回指定class的数组。如果目标数据不是JSON数组则返回 null。asList(class):返回指定类型的List集合。如果目标数据不是JSON数组则返回 null。

如果目标数据没能转换成给定的类型,则抛出 JWTDecodeException 异常。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有